package com.neusoft.databus.agent.parser.modbus;

import java.util.Arrays;

import org.springframework.util.StringUtils;

import com.neusoft.databus.common.bean.MetricBean;
import com.neusoft.databus.common.utils.DigitalUtils;

/**
 * Modbus ASCII parser <br >
 * 发送指令 3A 07 03 00 F8 00 34 CA 0D 0A => 3A 30 37 30 33 30 30 46 38 30 30 33 34
 * 43 41 0D 0A <br >
 *
 * @author naxiang
 */
public class ModBusASCIIParser extends ModBusParser {

    private static final String START_IDENTIFIER = "3A";
    private static final String END_IDENTIFIER = "0D0A";

    @Override
    public int getResponseHeaderLength() {
        //ASCII 3A 07 03 68 => 3A 30 37 30 33 36 38
        return 7;
    }

    @Override
    public byte[] generateReq(String slave, MetricBean metricBean) {
        final String commandCode = metricBean.getCommand().toUpperCase();
        return this.generateReq(slave, commandCode);
    }

    public byte[] generateReq(String slave, String commandCode) {
        if (StringUtils.isEmpty(commandCode) || StringUtils.isEmpty(commandCode.trim())) {
            return null;
        }
        String back = DigitalUtils.asciiToHex(DigitalUtils.lrc(slave + commandCode));
        back = ModBusASCIIParser.START_IDENTIFIER + back + ModBusASCIIParser.END_IDENTIFIER;
        return DigitalUtils.hexStringToBytes(back);
    }

    @Override
    public int expectedResDataLength(byte[] req) {
        final byte functionCode = req[1];
        final String str = DigitalUtils
                .hexToAscii(DigitalUtils.bytesToHexString(new byte[] {req[9], req[10], req[11], req[12] }));
        final int registerSize = DigitalUtils.bytesToUShort(DigitalUtils.hexStringToBytes(str), 0);

        //默认按功能码03,04处理
        int expected = this.getResponseHeaderLength() + (registerSize * 4) + 4;
        switch (functionCode) {
        case 0x01:
        case 0x02:
            expected = this.getResponseHeaderLength() + (((Double) Math.ceil(registerSize / 8.0)).intValue() * 2);
            break;
        default:
            break;
        }
        return expected;
    }

    /**
     * extract business data bytes(register data)
     *
     * @param packet the whole response bytes
     * @return
     */
    @Override
    public byte[] extractBusinessData(byte[] packet) {
        int realDataLengthByteOffset = this.getResponseHeaderLength() - 2;
        String str = DigitalUtils
                .hexToAscii(DigitalUtils.bytesToHexString(
                        new byte[] {packet[realDataLengthByteOffset], packet[realDataLengthByteOffset + 1] }));
        int maybeLen = DigitalUtils.bytesToUShort(DigitalUtils.hexStringToBytes(str), 0);
        if (maybeLen == 0) {
            realDataLengthByteOffset = this.getResponseHeaderLength();
            str = DigitalUtils
                    .hexToAscii(DigitalUtils.bytesToHexString(
                            new byte[] {packet[realDataLengthByteOffset], packet[realDataLengthByteOffset + 1] }));
            maybeLen = DigitalUtils.bytesToUShort(DigitalUtils.hexStringToBytes(str), 0);
        }
        final byte[] asciiPdu =
                Arrays.copyOfRange(packet, realDataLengthByteOffset + 1, realDataLengthByteOffset + 1 + (maybeLen * 2));

        final String asciiStr = DigitalUtils.hexToAscii(DigitalUtils.bytesToHexString(asciiPdu));

        return DigitalUtils.hexStringToBytes(asciiStr);
    }

    @Override
    public boolean validateResult(byte[] packet) {
        if (null == packet) {
            return false;
        }
        return true;
    }

}
